﻿//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  LIBRERIA: SIMA.CORE                                                                                                 //
//  DESARROLLADO POR JUAN CARLOS VEGA NEIRA                                                                             //
//  UNIVERSIDAD RICARDO PALMA                                                                                           //
//  CURSO DE TALLER DE GERENTCIA DE PROYECTOS                                                                           //
//  SEMESTRE 2010 - II                                                                                                  //
//  SEPTIEMBRE, 2010                                                                                                    //
//  TODOS LOS DERECHOS RESERVADOS                                                                                       //
//  VERSIÓN v1.0                                                                                                        //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Reflection;

using SIMA.Core.Data.Access;
using SIMA.Core.Utils;
using SIMA.Core.Exceptions;
using SIMA.Core.EventArgs;
using SIMA.Core.Enums;
using SIMA.Core.Attributes;
using SIMA.Core.Utils.Security;

namespace SIMA.Core.Data.Collection
{

    #region Atributtes

    [Serializable]

    #endregion

    public class SmartTreeContainer<T>:IDisposable
    {

        #region Consts

	    private const string S_DELIMITER = ",";
        private const string S_EXECUTEMESSAGE = "EJECUTADO";
        private const string S_INSERTMESSAGE = "AGREGADO";
        private const string S_UPDATEMESSAGE = "ACTUALIZADO";
        private const string S_DELETEMESSAGE = "ELIMINADO";
        private const string S_FAILEDMESSAGE = "ERROR";
        private const string S_FILEEXTENTION = ".csv";
    
	    #endregion
        
        #region	Fields
	
	    private string connectionString = string.Empty;
	    private bool haveLog = false;
	    private bool isReadOnly = false;
        private bool hasConnectionOpen = false;
        private string path = string.Empty;
        private string filename = string.Empty;

	    private TreeNode<T> beginNode = null;

	    private SqlConnection sqlConnection;
	    private SqlCommand sqlCommand;
	    private SqlDataAdapter sqlAdapter;

	    #endregion

        #region Properties

        /// <summary>
        /// Get a boolean if the container is writeable.
        /// </summary>
        public bool IsReadOnly
        {
            get 
            {
                return isReadOnly; 
            }
        }

        #endregion

        #region Events

        /// <summary>
        /// Event raise after updated an item of the table.
        /// </summary>
        public event EventHandler<UpdatedEventArgs> Updated;

        /// <summary>
        /// Event raise after deleted an item of the table.
        /// </summary>
        public event EventHandler<DeletedEventArgs> Deleted;

        /// <summary>
        /// Event raise after register an item of the table.
        /// </summary>
        public event EventHandler<InsertedEventArgs> Inserted;

        /// <summary>
        /// Event raise when an exception is catched.
        /// </summary>
        public event EventHandler<FailedEventArgs> Failed;

        #endregion

        #region Constructor

        public SmartTreeContainer()
        {
            Initializer();
        }

        public SmartTreeContainer(bool isReadOnly)
        {
            this.isReadOnly = isReadOnly;
            Initializer();
        }

        public SmartTreeContainer(bool isReadOnly, bool archived)
        {
            this.isReadOnly = isReadOnly;
            this.haveLog = archived;
            Initializer();
        }

        #endregion

        #region Destructor

        ~SmartTreeContainer()
        {
            this.Dispose();
        }

        #endregion

        #region Class Helper

        private class TreeNode<T>
        {
            private T data;
            private TreeNode<T> child;
            private TreeNode<T> brother;

            public T Data
            {
                get { return data; }
                set { data = value; }
            }

            public TreeNode<T> Child
            {
                get { return child; }
                set { child = value; }
            }

            public TreeNode<T> Brother
            {
                get { return brother; }
                set { brother = value; }
            }
        }

	    #endregion
   
        #region Private Methods

	    #region	Aux
                
	    private void Initializer()
	    {
            connectionString = DataAccess.GetConnectionString();
	        sqlConnection= new SqlConnection(connectionString);
            beginNode = Activator.CreateInstance<TreeNode<T>>();
            if (haveLog)
            {
                StringBuilder strBuilder = new StringBuilder();
                strBuilder.Append(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
                strBuilder.Append("\\");
                strBuilder.Append(DateTime.Now.ToLongDateString());
                strBuilder.Append(S_FILEEXTENTION);
                filename = strBuilder.ToString();
            }
	    }

        private bool AddToSQL(T parent, T item)
        {
            string query = string.Empty;
            try
            {
                Type tempParent = parent.GetType();
                TreeNode<T> _tmpParent = new SmartTreeContainer<T>.TreeNode<T>();
                _tmpParent.Data = parent;
                
                Inserted(this, new InsertedEventArgs(query, Operations.Insert));
                return true;
            }
            catch (IsReadOnlyException ex)
            {
                Failed(this, new FailedEventArgs(query, ex, Operations.Insert));
                return false;
            }
            catch (ValidationException ex)
            {
                Failed(this, new FailedEventArgs(query, ex, Operations.Insert));
                return false;
            }
            catch (CoreFaultException ex)
            {
                Failed(this, new FailedEventArgs(query, ex, Operations.Insert));
                return false;
            }
            catch (Exception ex)
            {
                Failed(this, new FailedEventArgs(query, ex, Operations.Insert));
                return false;
            }
            finally
            {
                sqlConnection.Close();
            }
        }

	    #endregion

	    #region Full Recursive
    	
	    private TreeNode<T> Find(TreeNode<T> BeginNode, TreeNode<T> ParentNode, T item)
	    {
            if (BeginNode.Data!=null)
            {
                if (!BeginNode.Data.Equals(item))
                {
                    if (BeginNode.Child != null)
                    {
                        return Find(BeginNode.Child, BeginNode, item);
                    }
                    else
                    {
                        return Find(BeginNode.Brother, BeginNode, item);
                    }
                }
                else
                {
                    return BeginNode;
                }
            }
            else
            {
                return BeginNode;
            }
    	
	    }

        private TreeNode<T> GetLastChild(TreeNode<T> lastBrother)
        {
            if (lastBrother.Brother != null)
            {
                return GetLastChild(lastBrother.Brother);
            }
            else
            {
                return lastBrother;
            }
        }

	    #endregion

	    #endregion
        
        #region Public Methods
        
        #region Normal Methods

        public void Add(T parent, T newChild)
        {
            
            TreeNode<T> child = Activator.CreateInstance<TreeNode<T>>();
            child.Data = newChild;
            child.Child = null;
            child.Brother = null;
            if (parent != null)
            {

                TreeNode<T> parentNode = Find(beginNode, null, parent);
                if (parentNode.Child != null)
                {
                    TreeNode<T> lastChild = GetLastChild(parentNode.Child);
                    lastChild.Brother = child;
                }
                else
                {
                    parentNode.Child = child;
                }
            }
            else
            {
                TreeNode<T> parentNode = Find(beginNode, null, parent);
                if (parentNode.Data == null)
                {
                    parentNode.Data = child.Data;
                }
                else
                {
                    if (parentNode.Brother != null)
                    {
                        TreeNode<T> lastBrother = GetLastChild(parentNode);
                        lastBrother.Brother = child;
                    }
                    else
                    {
                        parentNode.Child = child;
                    }
                }
            }
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }

        #endregion
        
        #region Extension Methods
        
        //public static void AddCHild(this T FirstPaternt, T item)
        //{
        //    TreeNode<T> parent = Find(beginNode, null, FirstPaternt);
        //    TreeNode<T> childNode = Activator.CreateInstance<TreeNode<T>>();
        //    childNode.Data = item;
        //    childNode.Brother = null;
        //    childNode.Child = null;
        //    if (parent.Child == null)
        //    {
        //        parent.Child = childNode;
        //    }
        //    else
        //    {
        //        TreeNode<T> lastChild = GetLastChild(parent.Child);
        //        lastChild.Brother = childNode;
        //    }
        //}	
        
        #endregion

	    #endregion

    }
}
